/*  File Name	: DirectoryService.cpp
 *  Author		: Pang Jiacai
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-10-30
 *  Description:
 */

#include "DirectoryService.h"
#include "DirectoryMonitor.h"

#define TIMER_VALUE			2		//定时器执行间隔(秒)
#define MAX_PACKET_IN_TIME	60		//如果在一个 TIMER_VALUE 时间内收到的数据包超过该值，则断开连接。防止数据包攻击

DirectoryService::DirectoryService(int p)
{
	this->reset();
}

DirectoryService::~DirectoryService()
{

}

int DirectoryService::open(void *p)
{
	if(this->monitor()->bind_service(this)<0)
	{
		return -1;
	}
	if(super::open(this->reactor())<0)
	{
		return -1;
	}

	if(this->start_timer(TimeValue(1),TimeValue(TIMER_VALUE))<0)
	{
		LOG((ERROR_LOG,"DirectoryService::open-->start_timer error,[ip:%s][port:%d]",
				this->conn_addr_,this->port_));
		return -1;
	}
	LOG((DEBUG_LOG,"DirectoryService::open-->[%s:%d]",this->conn_addr_,this->port_));
	return 0;
}

int DirectoryService::handle_input(int fd)
{
	this->recv_msg_count_++;
	return this->recv_msg();
}

int DirectoryService::handle_output(int fd)
{
	return 0;
}

int DirectoryService::handle_timeout(void)
{
	int fd = this->peer()->get_handle();
	if(fd==INVALID_HANDLER)
	{
		LOG((ERROR_LOG,"DirectoryService::handle_timeout-->[fd:%d][%s:%d]",
						fd,this->conn_addr_,this->port_));
		this->stop_timer();
//		this->monitor()->unbind_service(this);
//		this->recycle(this);
		this->monitor()->handle_close(this);
		return -1;
	}

	if(this->recv_msg_count_ >=MAX_PACKET_IN_TIME)
	{
		LOG((ERROR_LOG,"DirectoryService::handle_timeout-->[fd:%d][%s:%d][%d],too many packet",
				fd,this->conn_addr_,this->port_,this->recv_msg_count_));
		this->reactor()->remove_handler(fd,this);
	}
	this->recv_msg_count_ = 0;
	return 0;
}

int DirectoryService::handle_close(int handle, ReactorMask mask)
{
	super::handle_close();
	return this->monitor()->handle_close(this);
}

void DirectoryService::reset(void)
{
	this->server_id_ = 0;
	super::reset();
}

std::string DirectoryService::name(void)
{
	return std::string("DirectoryService");
}

const int DirectoryService::server_id(void)
{
	return this->server_id_;
}

void DirectoryService::server_id(int server_id)
{
	this->server_id_ = server_id;
}

const int DirectoryService::game_type(void)
{
	return this->game_type_;
}

void DirectoryService::game_type(int game_type)
{
	this->game_type_ = game_type;
}

int DirectoryService::recv_msg(const int limit_size)
{
	MessageBlock *mb = NULL;
	if(this->monitor()->msg_pool()->pop(mb)!=0)
	{
		LOG((ERROR_LOG,"DirectoryService::recv_msg-1->pop error"));
		return -1;
	}

	int len =0;
	bool has_data = false;
	do
	{
		mb->reset();
		len = super::recv_msg(mb, mb->size());
		if (len == -1 && (errno == EWOULDBLOCK || errno==EINTR))
		{
			this->monitor()->msg_pool()->push(mb);
			break;
		}
		else if (len <= 0)
		{
			LOG((DEBUG_LOG,"DirectoryService::recv_msg-->recv:[%d],error:[%d:%s]",
					len,errno,strerror(errno)));
			this->monitor()->msg_pool()->push(mb);
			return -1;
		}

		has_data = true;
		if (this->make_block(mb, len) == -1)
		{
			LOG((ERROR_LOG,"DirectoryService::recv_msg-->make_block error"));
			return -1;
		}
	}while (len > 0);

	if(!has_data)
	{
		return 0;
	}

	int result = 0;
	do
	{
		MessageBlock *mb = NULL;
		if(this->monitor()->msg_pool()->pop(mb)!=0)
		{
			LOG((ERROR_LOG,"DirectoryService::recv_msg-2->pop error"));
			return -1;
		}

		*mb	<<this->unique_id() << this->server_id();

		result = this->get_block(mb);
		if(result<0)
		{
			LOG((ERROR_LOG,"DirectoryService::recv_msg-->get_block error[%d]",result));
			this->monitor()->msg_pool()->push(mb);
			return -1;
		}
		else if(result==0)
		{
			this->monitor()->msg_pool()->push(mb);
			return 0;
		}
		this->monitor()->request_mb_push(mb);
	}
	while(result==2);
	return 0;
}

